﻿using Acme.BookStore.Storage.DTO;
using AutoMapper.Internal.Mappers;
using Microsoft.EntityFrameworkCore;
using OfficeOpenXml;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Uow;
using Volo.Abp.Users;

namespace Acme.BookStore.Storage
{
    public class InboundServices : CrudAppService<InboundManage, InboundManageDTO, Guid, PagedResultRequestDto, CreateUpdateInboundManageDTO, CreateUpdateInboundManageDTO>, IInboundManageServices
    {
        private readonly IRepository<Products, Guid> _productRepository;
        private readonly IRepository<InboundDetail, Guid> _detailRepository;
        private readonly ILogService _logService;
        private readonly IApprovalHistoryService _approvalHistoryService;
        private readonly ICurrentUser _currentUser;

        public InboundServices(
            IRepository<InboundManage, Guid> repository,
            IRepository<Products, Guid> productRepository,
            IRepository<InboundDetail, Guid> detailRepository,
            ILogService logService,
            IApprovalHistoryService approvalHistoryService,
            ICurrentUser currentUser
        ) : base(repository)
        {
            _productRepository = productRepository;
            _detailRepository = detailRepository;
            _logService = logService;
            _approvalHistoryService = approvalHistoryService;
            _currentUser = currentUser;
        }

        public override async Task<InboundManageDTO> CreateAsync(CreateUpdateInboundManageDTO input)
        {
            var entity = ObjectMapper.Map<CreateUpdateInboundManageDTO, InboundManage>(input);
            entity.Details.Clear();
            if (input.Details != null && input.Details.Any())
            {
                foreach (var detailDto in input.Details)
                {
                    var detail = new InboundDetail(Guid.NewGuid());
                    ObjectMapper.Map(detailDto, detail);
                    detail.InboundManageId = entity.Id;
                    entity.Details.Add(detail);
                }
            }
            await Repository.InsertAsync(entity, autoSave: true);

            await LogOperation(entity.Id, "新增", $"创建入库单：{entity.InboundOrderNumber}");

            var queryable = await Repository.GetQueryableAsync();
            var withDetails = await queryable
                .Include(x => x.Details)
                .FirstOrDefaultAsync(x => x.Id == entity.Id);

            return ObjectMapper.Map<InboundManage, InboundManageDTO>(withDetails);
        }

        private async Task LogOperation(Guid? inboundManageId, string operationType, string description)
        {
            var operatorName = _currentUser.UserName ?? "匿名";
            if (_logService != null)
            {
                await _logService.LogAsync(operatorName, operationType, description, inboundManageId);
            }
        }

        [UnitOfWork]
        public override async Task<InboundManageDTO> UpdateAsync(Guid id, CreateUpdateInboundManageDTO input)
        {
            var entity = await Repository.GetAsync(id);

            // 手动更新主实体的标量属性
            entity.InboundOrderNumber = input.InboundOrderNumber;
            entity.InboundType = input.InboundType;
            entity.State = input.State;
            entity.InboundDate = input.InboundDate;
            entity.WarehouseName = input.WarehouseName;
            entity.InboundGood = input.InboundGood;
            entity.Attn = input.Attn;
            entity.InboundQuantity = input.InboundQuantity;
            entity.InboundAmount = input.InboundAmount;
            entity.MakeSingle = input.MakeSingle;
            entity.MakeSingleTime = input.MakeSingleTime;
            entity.Reviewers = input.Reviewers;
            entity.ReviewTime = input.ReviewTime;

            // 删除原有明细（逐条删除，彻底清理跟踪）
            var oldDetails = await _detailRepository.GetListAsync(d => d.InboundManageId == id);
            foreach (var d in oldDetails)
            {
                // 恢复货品库存（减去原入库数量）
                var oldProduct = await _productRepository.FindAsync(d.ProductId);
                if (oldProduct != null)
                {
                    oldProduct.QuantityOnHand -= d.Quantity;
                    await _productRepository.UpdateAsync(oldProduct);
                }
                await _detailRepository.DeleteAsync(d);
            }
            await UnitOfWorkManager.Current.SaveChangesAsync(); // 立刻清理DbContext跟踪
                                                                // 新增新明细，强制生成新Id，避免EF Core跟踪冲突
            if (input.Details != null && input.Details.Any())
            {
                foreach (var detailDto in input.Details)
                {
                    var detailId = (detailDto.Id.HasValue && detailDto.Id.Value != Guid.Empty)
                        ? detailDto.Id.Value
                        : Guid.NewGuid();
                    var detail = new InboundDetail(detailId); // 用前端id或新id
                    ObjectMapper.Map(detailDto, detail); // 把其它属性映射到detail
                    detail.InboundManageId = id; // 确保外键已设置

                    // 自动补全货品信息
                    var product = await _productRepository.FindAsync(detailDto.ProductId);
                    if (product != null)
                    {
                        detail.ProductId = product.Id;
                        detail.ProductName = product.ProductName;
                        detail.ProductCode = product.ProductCode;
                        detail.ProductType = product.ProductType;
                        detail.Model = product.Model;
                        detail.Unit = product.Unit;

                        // 计算库存
                        detail.StockBefore = product.QuantityOnHand; // 操作前库存 = 货品当前库存
                        detail.StockAfter = product.QuantityOnHand + detail.Quantity; // 操作后库存 = 当前库存 + 入库数量

                        // 更新货品库存
                        product.QuantityOnHand = detail.StockAfter;
                        await _productRepository.UpdateAsync(product);
                    }
                    await _detailRepository.InsertAsync(detail);
                }
            }

            await UnitOfWorkManager.Current.SaveChangesAsync();
            await LogOperation(id, "修改", $"修改入库单：{input.InboundOrderNumber}");

            return ObjectMapper.Map<InboundManage, InboundManageDTO>(await Repository.GetQueryableAsync()
                .Result.Include(x => x.Details)
                .FirstOrDefaultAsync(x => x.Id == id));
        }

        public override async Task DeleteAsync(Guid id)
        {
            // 删除明细
            var details = await _detailRepository.GetListAsync(d => d.InboundManageId == id);
            foreach (var detail in details)
            {
                await _detailRepository.DeleteAsync(detail);
            }
            // 删除主表
            await Repository.DeleteAsync(id);
            await LogOperation(id, "删除", $"删除入库单：{id}");
        }

        public async Task<Stream> ExportToExcelAsync()
        {
            var items = await Repository.GetListAsync();

            ExcelPackage.LicenseContext = OfficeOpenXml.LicenseContext.NonCommercial;
            var package = new ExcelPackage();
            var worksheet = package.Workbook.Worksheets.Add("入库管理");

            worksheet.Cells[1, 1].Value = "入库单号";
            worksheet.Cells[1, 2].Value = "入库类型";
            worksheet.Cells[1, 3].Value = "状态";
            worksheet.Cells[1, 4].Value = "入库日期";
            worksheet.Cells[1, 5].Value = "仓库名称";
            worksheet.Cells[1, 6].Value = "入库货品";
            worksheet.Cells[1, 7].Value = "经办人";
            worksheet.Cells[1, 8].Value = "入库数量";
            worksheet.Cells[1, 9].Value = "入库金额";
            worksheet.Cells[1, 10].Value = "制单人";
            worksheet.Cells[1, 11].Value = "制单时间";
            worksheet.Cells[1, 12].Value = "审核人";
            worksheet.Cells[1, 13].Value = "审核时间";

            int row = 2;
            foreach (var item in items)
            {
                worksheet.Cells[row, 1].Value = item.InboundOrderNumber;
                worksheet.Cells[row, 2].Value = item.InboundType;
                worksheet.Cells[row, 3].Value = item.State;
                worksheet.Cells[row, 4].Value = item.InboundDate?.ToString("yyyy-MM-dd");
                worksheet.Cells[row, 5].Value = item.WarehouseName;
                worksheet.Cells[row, 6].Value = item.InboundGood;
                worksheet.Cells[row, 7].Value = item.Attn;
                worksheet.Cells[row, 8].Value = item.InboundQuantity;
                worksheet.Cells[row, 9].Value = item.InboundAmount;
                worksheet.Cells[row, 10].Value = item.MakeSingle;
                worksheet.Cells[row, 11].Value = item.MakeSingleTime.ToString("yyyy-MM-dd");
                worksheet.Cells[row, 12].Value = item.Reviewers;
                worksheet.Cells[row, 13].Value = item.ReviewTime?.ToString("yyyy-MM-dd");
                row++;
            }

            var stream = new MemoryStream();
            package.SaveAs(stream);
            stream.Position = 0;

            await LogOperation(null, "导出", "导出入库单Excel");

            return stream;
        }

        private async Task AddApprovalHistory(Guid inboundManageId, string operationType, string result, string comment, string operatorName = null)
        {
            var realOperatorName = operatorName ?? _currentUser.UserName ?? "匿名";
            if (_approvalHistoryService != null)
            {
                await _approvalHistoryService.AddHistoryAsync(inboundManageId, operationType, result, comment, realOperatorName);
            }
        }

        [UnitOfWork]
        public async Task ApproveAsync(Guid id, int state, string reviewers)
        {
            var entity = await Repository.GetAsync(id);

            if (entity.State == 1 || entity.State == 2) // 1: 已完成, 2: 已入库，禁止审核
            {
                throw new Volo.Abp.UserFriendlyException("只能审核待审核或已拒绝的数据！");
            }

            if (state != 1 && state != 3) // 1: 已完成, 3: 已拒绝
            {
                throw new Volo.Abp.UserFriendlyException("状态值不合法！");
            }

            entity.State = state;
            entity.Reviewers = reviewers;
            entity.ReviewTime = DateTime.Now;

            await LogOperation(id, "审核", $"审核入库单：{id}，结果：{(state == 1 ? "同意" : "拒绝")}");
            await AddApprovalHistory(entity.Id, "审核", state == 1 ? "同意" : "拒绝", "");
        }

        public override async Task<InboundManageDTO> GetAsync(Guid id)
        {
            var queryable = await Repository.GetQueryableAsync();
            var entity = await queryable
                .Include(x => x.Details)
                .FirstOrDefaultAsync(x => x.Id == id);

            return ObjectMapper.Map<InboundManage, InboundManageDTO>(entity);
        }

        public override async Task<PagedResultDto<InboundManageDTO>> GetListAsync(PagedResultRequestDto input)
        {
            var query = await Repository.GetQueryableAsync();
            var totalCount = await AsyncExecuter.CountAsync(query);
            var items = await AsyncExecuter.ToListAsync(query
                .OrderByDescending(x => x.CreationTime)
                .Skip(input.SkipCount)
                .Take(input.MaxResultCount));
            return new PagedResultDto<InboundManageDTO>(
                totalCount,
                ObjectMapper.Map<List<InboundManage>, List<InboundManageDTO>>(items)
            );
        }
    }
}

